#include "stdafx.h"
#include "MyH264Saver.h"
#include "libVideoSaver/cVideoSaveAvi.h"
#include "libVideoSaver/cVideoSaveFFMsvc.h"
#include "Plugins/dirHelper/cDirHelper.h"
#include "Plugins/customFuncHelper/cCustomFuncHelper.h"
#include "Plugins/threadHelper/cThreadHelper.h"
#include "Plugins/timeHelper/cTimeHelper.h"

#include <algorithm>
#include <string.h>
#include <stdarg.h>
#include <thread>

namespace libcvos_vfr
{
    using namespace libcvos_vfr::Helper;

	typedef void(*IMAGE_FILE_CALLBACK)(void*, const char*);
    const int LOG_BUF_LEN = 1024*1024;

//#define WRITE_LOG(fmt,...) LOG_FMT_INFO("%s:: " fmt, __FUNCTION__,##__VA_ARGS__);

	MyH264Saver::MyH264Saver() :
		m_bExit(false),
		m_iSaveH264Flag(0),
		m_iTimeFlag(0),
		M_iStopTimeFlag(TIME_FLAG_UNDEFINE),
		m_iTmpTime(0),
		m_iMode(-1),
		m_lastvideoidx(-1),
		m_iFrameLogID(0),
		m_iVideoLogID(1),
		m_bFirstSave(false),
		m_bWriteLog(false),		
		m_lDataStructVector(VIDEO_FRAME_LIST_SIZE),
		m_hVideoSaver(NULL),
		m_pUserData(NULL),
		m_pCallbackFunc(NULL)
	{
		Init();
	}

	MyH264Saver::~MyH264Saver()
	{		
		SetSaveFlag(false);
		StopProcessThread();

		LOG_FMT_INFO("~MyH264Saver:: release data begin.");
		ClearData();
		LOG_FMT_INFO("~MyH264Saver:: release data finish.");
		UnInit();
	}

	bool MyH264Saver::StartProcess(int iType /*= 0*/)
	{
		SetProcessMode(iType);
		StartProcessThread();
		return true;
	}

	int MyH264Saver::GetProcessMode()
	{
		std::lock_guard<std::mutex> guard(m_Locker);
		int iValue = 0;

		iValue = m_iMode;

		return iValue;
	}

	void MyH264Saver::SetProcessMode(int iValue)
	{
		std::lock_guard<std::mutex> guard(m_Locker);
		m_iMode = iValue;
	}

	bool MyH264Saver::addDataStruct(CustH264Struct* pDataStruct)
	{
		if (pDataStruct == NULL)
		{
			return false;
		}
		//char buf[256] = { 0 };
		//sprintf_s(buf, "%ld\n", pDataStruct->m_llFrameTime);
		//OutputDebugString(buf);

		std::shared_ptr<CustH264Struct> pData = std::shared_ptr<CustH264Struct>(pDataStruct);
		if (GetProcessMode() == 1)
		{
			std::lock_guard<std::mutex> guard(m_DataListLocker);

			if (m_lDataStructList.size() > VIDEO_FRAME_LIST_SIZE)
			{
				auto tempData = m_lDataStructList.front();
				m_lDataStructList.pop_front();
				//LOG_FMT_INFO("addDataStruct:: size > %d, erase front, frame time = %I64u ", VIDEO_FRAME_LIST_SIZE, tempData->m_llFrameTime);
			}
			m_lDataStructList.push_back(pData);
		}
		else
		{
			m_lDataStructVector.AddOneData(pData);
		}

		return true;
	}

    bool MyH264Saver::StartSaveH264_unlimited(uint64_t beginTimeStamp, const char* pchFilePath)
	{
		//qDebug()<< "StartSaveH264 :"<< "beginTimeStamp "<< beginTimeStamp;
		LOG_FMT_INFO(" beginTimeStamp =  %I64u , pchFilePath = %s", beginTimeStamp, pchFilePath);
		int iSaveFlag = GetSaveFlag();
		while (SAVING_FLAG_NOT_SAVE != iSaveFlag)
		{
			switch (iSaveFlag)
			{
			case SAVING_FLAG_SAVING:
				LOG_FMT_INFO(" current save flag == SAVING_FLAG_SAVING, set to SAVING_FLAG_SHUT_DOWN to finish writing video file. ");
				SetSaveFlag(SAVING_FLAG_SHUT_DOWN);
				break;
			case SAVING_FLAG_SHUT_DOWN:
				LOG_FMT_INFO(" current save flag == SAVING_FLAG_SHUT_DOWN wait finish. ");
				break;
			default:
				LOG_FMT_INFO(" current save flag = %d, unknow. ", iSaveFlag);
				break;
			}
			iSaveFlag = GetSaveFlag();
			Tool_sleepForMillsecond(100);
		}
		SetSavePath(pchFilePath, strlen(pchFilePath));
		SetStartTimeFlag(beginTimeStamp);
		SetIfFirstSave(true);
		SetStopTimeFlag(TIME_FLAG_UNDEFINE);
		if (GetProcessMode() != 1)
		{
			SetSaveFlag(SAVING_FLAG_SAVING);
		}
		m_lastvideoidx = -1;
		return true;
	}

    bool MyH264Saver::StopSaveH264_unlimited(uint64_t TimeFlag)
	{
		//SetSaveFlag(SAVING_FLAG_SHUT_DOWN);
		SetStopTimeFlag(TimeFlag);
		if (GetProcessMode() == 1)
		{
			SetSaveFlag(SAVING_FLAG_SAVING);
		}
		return true;
	}

    bool MyH264Saver::SaveH264_CaptureClip(uint64_t beginTimeStamp, uint64_t endTimeStamp, const char *pchFilePath)
    {
		LOG_FMT_INFO("beginTimeStamp = %I64u, endTimeStamp = %I64u, pchFilePath = %s", beginTimeStamp, endTimeStamp, pchFilePath);
		if(m_iMode != type_capture_clip)
		{
			LOG_FMT_INFO("m_iMode!= type_capture_clip, return false.");
			return false;
		}
		{
			std::lock_guard<std::mutex> guard(m_txVideoFileList);
			if(m_lVideoFileList.size() > 3)
			{			
				std::shared_ptr<videoFileNode> pVideoFileNode = m_lVideoFileList.front();
				m_lVideoFileList.pop_front();
				std::string strFileName = pVideoFileNode->m_strFileName;
				LOG_FMT_INFO("m_lVideoFileList.size() > 3, remove first: %s.", strFileName.c_str());
			}
			std::shared_ptr<videoFileNode> pVideoFileNode = std::make_shared<videoFileNode>( pchFilePath, beginTimeStamp, endTimeStamp, 25);
			if(pVideoFileNode)
			{
				m_lVideoFileList.push_back(pVideoFileNode);
				LOG_FMT_INFO("add videoFileNode to m_lVideoFileList");
			}
		}
        return true;
    }

    int MyH264Saver::saveFrameListToVideo(std::deque<std::shared_ptr<CustH264Struct> > &frameList, const char *fileName)
    {
        if (frameList.empty() || NULL == fileName || m_hVideoSaver == NULL)
        {
			LOG_FMT_INFO("frameList.empty() || NULL == fileName || m_hVideoSaver == NULL");
            return -1;
        }

        bool bFirstFrame = true;
        bool bFindFirstIFrame = false;
        int iVideoWidth = 0;
        int iVideoHeight = 0;
        int iFlag = 0;
        int iIndex = 0;
        for (auto frame : frameList)
        {
            iIndex ++;
            if (bFirstFrame)
            {
                LOG_FMT_INFO("begin to save video,file = %s", fileName);
                iVideoWidth = frame->m_iWidth;
                iVideoHeight = frame->m_iHeight;

                iFlag = m_hVideoSaver->CreateVideoFile(fileName, iVideoWidth, iVideoHeight, 25);
                if (0 != iFlag)
                {
                    LOG_FMT_INFO("CreateVideoFile failed  return code = %d", iFlag);
                    break;
                }
                else
                {
                    LOG_FMT_INFO("CreateVideoFile success");
                    bFirstFrame = false;
                }
            }
            if (frame->m_isIFrame)
            {
                bFindFirstIFrame = true;
            }
            if (bFindFirstIFrame)
            {
                iFlag = m_hVideoSaver->WriteH264Frame(0, frame->m_pbH264FrameData, frame->m_iDataSize);
                // LOG_FMT_INFO("Video_WriteH264Frame(%p, %lu) = %d, index = %d",
                //              frame->m_pbH264FrameData, frame->m_iDataSize, iFlag, iIndex);
            }
        }
        iFlag = m_hVideoSaver->CloseVideoFile();
        LOG_FMT_INFO("video save finish, iFlag = %d \n", iFlag);
        return iFlag;
    }

    std::deque<std::shared_ptr<CustH264Struct> > MyH264Saver::getFrameListByTime(uint64_t beginTime, uint64_t endTime)
    {
        LOG_FMT_INFO("beginTime = %llu, endTime= %llu", beginTime, endTime);
        std::deque<std::shared_ptr<CustH264Struct> > videoFrameList;
        if(beginTime >= endTime)
        {
            LOG_FMT_ERR("beginTime >= endTime, time is invalid.");
            return videoFrameList;
        }

        uint32_t iNeedFrameCount = (endTime - beginTime)/40;
        LOG_FMT_INFO("need video frame count = %u", iNeedFrameCount);

        if (GetProcessMode() != 1)
        {
            LOG_FMT_ERR("GetProcessMode != 1, operation is not supported.");
            return videoFrameList;
        }

		std::deque<std::shared_ptr<CustH264Struct > >::iterator iterFirstIFrame;
        std::deque<std::shared_ptr<CustH264Struct > >::iterator iterEnd;
        size_t iBeginIndex = 0;
        bool bFindFirstIFrame = false;

        std::lock_guard<std::mutex> guard(m_DataListLocker);

        size_t iFrameListSize = m_lDataStructList.size();

        iterFirstIFrame = std::find_if(std::begin(m_lDataStructList),
            std::end(m_lDataStructList),
            [beginTime](std::shared_ptr<CustH264Struct > h264Data)
        {
            return (h264Data->m_llFrameTime >= beginTime && h264Data->m_isIFrame);
        }
        );

        if (iterFirstIFrame != std::end(m_lDataStructList))
        {
            iBeginIndex = std::distance(std::begin(m_lDataStructList), iterFirstIFrame);
            LOG_FMT_INFO("Find the I frame that fully meets the conditions (I frame, time) , index = %u", iBeginIndex);
            if ( iFrameListSize >= iBeginIndex + iNeedFrameCount)
            {
                LOG_FMT_INFO(" iFrameListSize >= iBeginIndex + iNeedFrameCount");

                iterEnd = iterFirstIFrame + iNeedFrameCount;
                LOG_FMT_INFO("iListSize(%d) >= (iBeginIndex + iFrameCount)(%d),can save a specified number of frames ",
                    iFrameListSize,
                    iBeginIndex + iNeedFrameCount);
            }
            else if ( iFrameListSize >= iNeedFrameCount )
            {
                LOG_FMT_INFO(" iFrameListSize >= iNeedFrameCount");
                int iNewIndex = 0;
                for (auto iter = std::end(m_lDataStructList) - iNeedFrameCount; iter > std::begin(m_lDataStructList) ; iter--)
                {
                    if ((*iter)->m_isIFrame)
                    {
                        bFindFirstIFrame = true;
                        iNewIndex = std::distance(std::begin(m_lDataStructList), iter);
                        break;
                    }
                }

                if(bFindFirstIFrame)
                {
                    LOG_FMT_INFO(" iFrameCount(%u) < iListSize(%u) < iBeginIndex+ iFrameCount (%u), search forward, get new index %d",
                        iNeedFrameCount,
                        iFrameListSize,
                        iBeginIndex + iNeedFrameCount,
                        iNewIndex);
                    iBeginIndex = iNewIndex;

                    iterFirstIFrame = std::begin(m_lDataStructList) + iBeginIndex;
                    iterEnd = iterFirstIFrame + iNeedFrameCount;
                }
                else
                {
                    LOG_FMT_INFO("can not find the first i frame.");
                }
            }
            else
            {
                LOG_FMT_INFO(" iFrameListSize < iNeedFrameCount ");
                for (auto iter = std::begin(m_lDataStructList); iter != std::end(m_lDataStructList); iter++)
                {
                    if ((*iter)->m_isIFrame)
                    {
                        bFindFirstIFrame = true;
                        iBeginIndex = std::distance(std::begin(m_lDataStructList), iter);
                        break;
                    }
                }

                if(bFindFirstIFrame)
                {
                    LOG_FMT_INFO("iListSize(%u) <  iFrameCount(%u),Save from the beginning to the end, the count of frames is  %u",
                        iFrameListSize,
                        iNeedFrameCount,
                        iFrameListSize - iBeginIndex);

                    iterFirstIFrame = std::begin(m_lDataStructList) + iBeginIndex;
                    iterEnd = std::end(m_lDataStructList);
                }
                else
                {
                    LOG_FMT_INFO("can not find the first i frame.");
                }
            }
        }
		else
		{
			LOG_FMT_INFO("can not find the first i frame that match begin time, Use the oldest video cache instead.");
			iterFirstIFrame = std::find_if(std::begin(m_lDataStructList),
										   std::end(m_lDataStructList),
										   [beginTime](std::shared_ptr<CustH264Struct> h264Data)
										   {
											   return (h264Data->m_isIFrame);
										   });			
			if (iterFirstIFrame != m_lDataStructList.end())
			{
				iBeginIndex = std::distance(std::begin(m_lDataStructList), iterFirstIFrame);
				if (iFrameListSize < iNeedFrameCount || iFrameListSize < (iBeginIndex + iNeedFrameCount))
				{
					LOG_FMT_INFO("iFrameListSize < iNeedFrameCount, find the nearly i frame, save to the end.");
					iterEnd = std::end(m_lDataStructList);
				}
				else
				{
					iterEnd = iterFirstIFrame + iNeedFrameCount;
				}
			}
		}

		if(iterFirstIFrame == m_lDataStructList.end())
        {
            LOG_FMT_ERR("match i frame failed.");
            return videoFrameList;
        }

        LOG_FMT_INFO("copy data to list.");
        for(auto iter = iterFirstIFrame; iter != iterEnd ;iter ++ )
        {
            if(iter == m_lDataStructList.end())
            {
                LOG_FMT_INFO("list end, finish.");
                break;
            }

            std::shared_ptr<CustH264Struct > pFrame = *iter;
            if(pFrame)
            {
                // LOG_FMT_INFO("index = %u, time = %llu, isIframe = %d, data=%p, len=%lu",
                //              pFrame->index,
                //              pFrame->m_llFrameTime,
                //              pFrame->m_isIFrame,
                //              pFrame->m_pbH264FrameData,
                //              pFrame->m_iDataSize);
                videoFrameList.push_back(std::shared_ptr<CustH264Struct>(CustH264Struct::copyData(pFrame.get())));
            }
            else
            {
                LOG_FMT_ERR("frame is invalid.");
            }
        }
        LOG_FMT_INFO("final list size = %u", videoFrameList.size());

        return videoFrameList;
    }

	void MyH264Saver::ProcessH264Data()
	{
		if (GetProcessMode() == type_unlimited)
		{
			processH264Data_unlimited();
		}
		else if(GetProcessMode() == type_capture_clip)
		{
			processH264Data_CaptureClip();
		}
	}

	uint32_t MyH264Saver::processH264Data_unlimited()
	{
		LOG_FMT_INFO("begin.");
		if(m_hVideoSaver == NULL)
		{
			LOG_FMT_ERR("m_hVideoSaver == NULL.");
			return -1;
		}
		int  iSaveFlag = 0;
		int iVideoWidth = -1;
		int iVideoHeight = -1;
		int iFlag = 1;

		unsigned long long iCurrentFrameTimeFlag = TIME_FLAG_UNDEFINE;
		unsigned long long iLastFrameTimeFlag = TIME_FLAG_UNDEFINE;
		unsigned long long iVideoStopTimeFlag = TIME_FLAG_UNDEFINE;

		unsigned long long iLastSaveFlag = 0;
		unsigned long long iVideoBeginTimeFlag = 0;
		unsigned long long iTimeNowFlag = 0;

		while (!GetIfExit())
		{
			char buf[256] = { 0 };
			iVideoStopTimeFlag = GetStopTimeFlag();
			iVideoBeginTimeFlag = GetStartTimeFlag();
			iTimeNowFlag = Tool_GetTickCount();

			iSaveFlag = GetSaveFlag();

			if (iSaveFlag != iLastSaveFlag)
			{
				LOG_FMT_INFO("stop time flag change, lastStopTimeFlag =  %I64u  , current Stop time flag =  %I64u  , system time Now =  %I64u  ,  video beginTIme =  %I64u , save flag = %d\n",
					iLastSaveFlag,
					iVideoStopTimeFlag,
					iTimeNowFlag,
					iVideoBeginTimeFlag,
					iSaveFlag);
				iLastSaveFlag = iSaveFlag;
			}

			std::shared_ptr<CustH264Struct > pData = NULL;
			switch (iSaveFlag)
			{
			case SAVING_FLAG_NOT_SAVE:

				Tool_sleepForMillsecond(1);
				break;
			case SAVING_FLAG_SAVING:

				{
					if(GetIfFirstSave())
					{
						iLastFrameTimeFlag = iVideoBeginTimeFlag;
						LOG_FMT_INFO("GetIfFirstSave = 1, set iLastFrameTimeFlag = %I64u", iLastFrameTimeFlag);
					}
					int iFlag = -1;
					std::lock_guard<std::mutex> guard(m_DataListLocker);

					auto iter_begin = std::find_if(m_lDataStructList.begin(), m_lDataStructList.end(), [&](std::shared_ptr<CustH264Struct > pData){
						if (pData!= NULL
							&& pData->m_llFrameTime > iLastFrameTimeFlag
							&& pData->m_llFrameTime < iVideoStopTimeFlag)
						{	
							return true;
						}
						return false;
					});

					auto iterStopFrame = std::find_if(m_lDataStructList.begin(), m_lDataStructList.end(), [&](std::shared_ptr<CustH264Struct > pData){
						if (pData!= NULL
							&& pData->m_llFrameTime > iVideoStopTimeFlag)
						{
							return true;
						}
						return false;
					});					

					if (iter_begin == m_lDataStructList.end())
					{
						if(iterStopFrame == m_lDataStructList.end())
						{
							// LOG_FMT_INFO("iter_begin and iterStopFrame == end");
							continue;
						}						
						LOG_FMT_INFO("iter_begin == end");
					}
					for(auto iter = iter_begin; iter!= iterStopFrame; iter++)
					{
						if(iter == m_lDataStructList.end())
						{
							LOG_FMT_INFO("iter_begin == end");
							break;
						}
						std::shared_ptr<CustH264Struct > pData = *iter;
						if (pData == NULL)
						{
							LOG_FMT_INFO("pData == NULL");
							continue;
						}
						if(GetIfFirstSave())
						{
							if(pData->m_isIFrame)
							{
								iFlag = m_hVideoSaver->CreateVideoFile(GetSavePath(), pData->m_iWidth, pData->m_iHeight, 25);
								LOG_FMT_INFO("CreateVideoFile = %d", iFlag);
								if(iFlag == 0)
								{
									SetIfFirstSave(false);
									iFlag = m_hVideoSaver->WriteH264Frame(pData->m_isIFrame == 0 ? false : true, pData->m_pbH264FrameData, pData->m_iDataSize);
									iLastFrameTimeFlag = pData->m_llFrameTime;
									// break;
								}
							}
						}
						else
						{
							iFlag = m_hVideoSaver->WriteH264Frame(pData->m_isIFrame == 0 ? false : true, pData->m_pbH264FrameData, pData->m_iDataSize);
							iLastFrameTimeFlag = pData->m_llFrameTime;
						}
					}
					if(iterStopFrame != m_lDataStructList.end())
					{
						iFlag = m_hVideoSaver->WriteH264Frame((*iterStopFrame)->m_isIFrame == 0 ? false : true, (*iterStopFrame)->m_pbH264FrameData, (*iterStopFrame)->m_iDataSize);
						SetSaveFlag(SAVING_FLAG_SHUT_DOWN);
						LOG_FMT_INFO("iterStopFrame != m_lDataStructList.end(), set SAVING_FLAG_SHUT_DOWN");
						continue;
					}
				}				

				break;
			case SAVING_FLAG_SHUT_DOWN:
				LOG_FMT_INFO("SAVING_FLAG_SHUT_DOWN.\n");
				m_hVideoSaver->CloseVideoFile();
				SetIfFirstSave(true);
				SetSaveFlag(SAVING_FLAG_NOT_SAVE);
				SendFileName(GetSavePath());

				break;
			default:
				LOG_FMT_INFO("MyH264Saver::processH264Data default break.\n");
				break;
			}
		}

		LOG_FMT_INFO("finish.\n");
		return 0;
	}

	uint32_t MyH264Saver::processH264Data_CaptureClip()
	{
		LOG_FMT_INFO("begin.");
		if(m_hVideoSaver == NULL)
		{
			LOG_FMT_ERR("m_hVideoSaver == NULL.");
			return -1;
		}

		while (!GetIfExit())
		{
			std::shared_ptr<videoFileNode> pFileNode;
			std::unique_lock<std::mutex> lock(m_txVideoFileList);
			m_conFile.wait_for(lock, std::chrono::milliseconds(100), [this]()
							   { return (!m_lVideoFileList.empty() || GetIfExit()); });

			if (!m_lVideoFileList.empty())
			{
				pFileNode = m_lVideoFileList.front();
				m_lVideoFileList.pop_front();
				lock.unlock();
			}
			if (pFileNode == NULL)
				continue;

			std::deque<std::shared_ptr<CustH264Struct> > pFrameList = getFrameListByTime(pFileNode->dw64BeginTimeTick, pFileNode->dw64EndTimeTick);
			if (pFrameList.size() == 0)
			{
				LOG_FMT_INFO("pFrameList.size() == 0");
				continue;
			}

			if(saveFrameListToVideo(pFrameList, pFileNode->m_strFileName.c_str()) == 0)
			{
				SendFileName(pFileNode->m_strFileName.c_str());
			}
			pFrameList.clear();
		}
		LOG_FMT_INFO("finish.");
		return 0;
	}

	void MyH264Saver::SetFileNameCallback(void *pUserData, void *pCallbackFunc)
	{
		std::lock_guard<std::mutex> guard(m_Locker);
		m_pUserData = pUserData;
		m_pCallbackFunc = pCallbackFunc;
	}

	void MyH264Saver::SendFileName(const char *fileName)
	{
		std::lock_guard<std::mutex> guard(m_Locker);
		if (m_pCallbackFunc)
		{
			((IMAGE_FILE_CALLBACK)m_pCallbackFunc)(m_pUserData, fileName);
		}
	}

	void MyH264Saver::SetIfExit(bool bValue)
	{
		std::lock_guard<std::mutex> guard(m_Locker);
		m_bExit = bValue;
	}

	bool MyH264Saver::GetIfExit()
	{
		std::lock_guard<std::mutex> guard(m_Locker);
		return m_bExit;
	}

	void MyH264Saver::SetSaveFlag(int iValue)
	{
		LOG_FMT_INFO("MyH264Saver::SetSaveFlag %d", iValue);
		std::lock_guard<std::mutex> guard(m_Locker);
		m_iSaveH264Flag = iValue;
	}

	int MyH264Saver::GetSaveFlag()
	{
		int iValue = false;
		std::lock_guard<std::mutex> guard(m_Locker);
		iValue = m_iSaveH264Flag;

		return iValue;
	}

    void MyH264Saver::SetStartTimeFlag(uint64_t iValue)
	{
		LOG_FMT_INFO("%I64u", iValue);
		std::lock_guard<std::mutex> guard(m_Locker);
		m_iTimeFlag = iValue;
		m_iTmpTime = iValue;
	}

    uint64_t MyH264Saver::GetStartTimeFlag()
	{
        uint64_t iValue = false;
		std::lock_guard<std::mutex> guard(m_Locker);
		iValue = m_iTimeFlag;

		return iValue;
	}

    void MyH264Saver::SetStopTimeFlag(uint64_t iValue)
	{
		LOG_FMT_INFO(" %I64u ", iValue);
		std::lock_guard<std::mutex> guard(m_Locker);
		M_iStopTimeFlag = iValue;
	}

    uint64_t MyH264Saver::GetStopTimeFlag()
	{
		std::lock_guard<std::mutex> guard(m_Locker);
        uint64_t iValue = false;
		iValue = M_iStopTimeFlag;

		return iValue;
	}

	void MyH264Saver::SetIfFirstSave(bool bValue)
	{
		LOG_FMT_INFO("MyH264Saver::SetIfFirstSave %d", bValue);
		std::lock_guard<std::mutex> guard(m_Locker);
		m_bFirstSave = bValue;
	}

	bool MyH264Saver::GetIfFirstSave()
	{
		bool bValue = false;
		std::lock_guard<std::mutex> guard(m_Locker);
		bValue = m_bFirstSave;

		return bValue;
	}

	void MyH264Saver::SetSavePath(const char* filePath, size_t bufLength)
	{
		LOG_FMT_INFO("MyH264Saver::SetSavePath %s", filePath);
		std::lock_guard<std::mutex> guard(m_Locker);
		if (bufLength < sizeof(m_chFilePath))
		{
			memcpy(m_chFilePath, filePath, bufLength);
			m_chFilePath[bufLength] = '\0';
		}
	}

	const char* MyH264Saver::GetSavePath()
	{
		const char* pValue = NULL;
		std::lock_guard<std::mutex> guard(m_Locker);
		pValue = m_chFilePath;

		return pValue;
	}

    void MyH264Saver::WriteFormatLog(const char *szfmt, ...)
    {
        if (!m_bWriteLog)
            return;
        if(!m_pLogBuf)
            return;
        memset(m_pLogBuf, '\0', LOG_BUF_LEN);

        va_list arg_ptr;
        va_start(arg_ptr, szfmt);
        vsnprintf(m_pLogBuf, LOG_BUF_LEN, szfmt, arg_ptr);
        va_end(arg_ptr);

        char chBuffer1[256] = { 0 };
        // strcpy(chBuffer1, Tool_get_current_dir().c_str());
		unsigned int iLen = strlen(chBuffer1);
		Tool_get_current_dir(chBuffer1, &iLen);

        DateTimeWithMilsec timeStruct;
        Tool_GetDateTimeWithMillisecond(&timeStruct);

        strcat(chBuffer1, "/XLWLog/");
        Tool_make_dirs(chBuffer1);

        char chLogFileName[512] = { 0 };
        sprintf(chLogFileName, "%s/Video_%d-%02d_%02d.log",
            chBuffer1,
            timeStruct.year,
            timeStruct.month,
            timeStruct.day);

        FILE *file = NULL;
        file = fopen(chLogFileName, "a+");
        if (file)
        {
            fprintf(file, "[%04d-%02d-%02d %02d:%02d:%02d:%03lld] : %s\n",
                timeStruct.year,
                timeStruct.month,
                timeStruct.day,
                timeStruct.hour,
                timeStruct.minute,
                timeStruct.second,
                timeStruct.millisecond,
                m_pLogBuf);

            fclose(file);
            file = NULL;
        }
	}

	void MyH264Saver::Init()
	{		
		if(m_hVideoSaver == NULL)
		{
			// m_hVideoSaver = new cVideoSaveAvi();
			m_hVideoSaver = new cVideoSaveFFMsvc();
			m_hVideoSaver->Init();
		}

		memset(m_chFilePath, '\0', sizeof(m_chFilePath));
		memset(m_chCurrentPath, '\0', sizeof(m_chCurrentPath));		
		unsigned int iLen = strlen(m_chCurrentPath);
		Tool_get_current_dir(m_chCurrentPath, &iLen);

        m_pLogBuf = new char[LOG_BUF_LEN];
        memset(m_pLogBuf, '\0', LOG_BUF_LEN);
	}

    void MyH264Saver::UnInit()
    {
		if (m_hVideoSaver != NULL)
		{
			m_hVideoSaver->Uninit();
			delete m_hVideoSaver;
			m_hVideoSaver = NULL;
		}
		LOG_FMT_INFO("~MyH264Saver:: Video_CloseProcessHandle finish.");
		if(m_pLogBuf)
		{
			delete[] m_pLogBuf;
			m_pLogBuf = NULL;
		}
    }

    void MyH264Saver::StartProcessThread()
    {
		SetIfExit(false);
		if (!m_ThreadSaveH264.joinable())
		{
			m_ThreadSaveH264 = std::thread(&MyH264Saver::ProcessH264Data, this);
		}
    }

    void MyH264Saver::StopProcessThread()
    {
		SetIfExit(true);
		m_conFile.notify_all();
		if (m_ThreadSaveH264.joinable())
		{
			m_ThreadSaveH264.join();
		}
    }
    
	void MyH264Saver::ClearData()
    {
		std::lock_guard<std::mutex> guard(m_DataListLocker);
		m_lDataStructList.clear();
    }
}
